/**
 * Copyright 2013 ABSir's Studio
 * 
 * All right reserved
 *
 * Create on 2013-7-11 下午2:58:07
 */
package com.absir.android.context;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.absir.android.context.annotation.AfterCreate;
import com.absir.android.context.annotation.BeforeCreate;
import com.absir.bean.inject.InjectInvoker;
import com.absir.bean.inject.InjectMethod;
import com.absir.bean.inject.value.InjectType;
import com.absir.core.kernel.KernelCollection;
import com.absir.core.kernel.KernelLang.BreakException;
import com.absir.core.kernel.KernelLang.CallbackBreak;
import com.absir.core.kernel.KernelReflect;

/**
 * @author absir
 * 
 */
public class ContextUtils {

	/**
	 * @param contextType
	 * @return
	 */
	public static InjectInvoker[][] getCreateInvokers(Class<?> contextType) {
		return getCreateInvokers(contextType, false);
	}

	/** Context_Type_Map_InjectInvokes */
	private static final Map<Class<?>, InjectInvoker[][]> Context_Type_Map_InjectInvokes = new HashMap<Class<?>, InjectInvoker[][]>();

	/**
	 * @param context
	 * @param singleton
	 * @return
	 */
	public static InjectInvoker[][] getCreateInvokers(final Class<?> contextType, boolean singleton) {
		InjectInvoker[][] injectInvokers = singleton ? null : Context_Type_Map_InjectInvokes.get(contextType);
		if (injectInvokers != null) {
			return injectInvokers;
		}

		final List<InjectInvoker> bInvokerList = new ArrayList<InjectInvoker>();
		final List<InjectInvoker> bInvokerScope = new ArrayList<InjectInvoker>();
		final List<InjectInvoker> aInvokerList = new ArrayList<InjectInvoker>();
		final List<InjectInvoker> aInvokerScope = new ArrayList<InjectInvoker>();
		final Set<Method> iMethodSet = new HashSet<Method>();

		KernelReflect.doWithClasses(contextType, new CallbackBreak<Class<?>>() {

			@Override
			public void doWith(Class<?> template) throws BreakException {
				// TODO Auto-generated method stub
				for (Method method : template.getDeclaredMethods()) {
					if (method.getAnnotation(BeforeCreate.class) != null) {
						method = KernelReflect.declaredMethod(contextType, method.getName(), method.getParameterTypes());
						if (method != null && iMethodSet.add(method)) {
							bInvokerScope.add(new InjectMethod(method, null, InjectType.Required));
						}

					} else if (method.getAnnotation(AfterCreate.class) != null) {
						method = KernelReflect.declaredMethod(contextType, method.getName(), method.getParameterTypes());
						if (method != null && iMethodSet.add(method)) {
							aInvokerScope.add(new InjectMethod(method, null, InjectType.Required));
						}
					}
				}

				bInvokerList.addAll(0, bInvokerScope);
				aInvokerList.addAll(0, aInvokerScope);
				bInvokerScope.clear();
				aInvokerScope.clear();
			}
		});

		injectInvokers = new InjectInvoker[][] { KernelCollection.toArray(bInvokerList, InjectInvoker.class),
				KernelCollection.toArray(aInvokerList, InjectInvoker.class) };
		if (singleton) {
			Context_Type_Map_InjectInvokes.put(contextType, injectInvokers);
		}

		return injectInvokers;
	}
}
